package com.mastercard.labs

import org.apache.shiro.SecurityUtils
import org.apache.shiro.authc.AuthenticationException
import org.apache.shiro.authc.UsernamePasswordToken
import org.apache.shiro.web.util.SavedRequest
import org.apache.shiro.web.util.WebUtils
import cr.co.arquetipos.crypto.Blowfish
import java.net.*;

class AuthController {
    def shiroSecurityManager
	def shiroSecurityService
	def mailService
	def userService
	def smsService
	def password = "se19team2s"
    def index = { redirect(action: "login", params: params) }

    def login = {
        return [ username: params.username?.toUpperCase(), rememberMe: (params.rememberMe != null), targetUri: params.targetUri ]
    }
	def register = {
		def user = new User(params)
		if(request.method == 'POST') {
			if (!params.username) {
				log.info "'username' not provided during registration - probably a spam bot."
				flash.message= "You must provide a username!"
				render (model: [params:params])
				return
			}

			if(params.password != params.password2) {
					flash.message = "password not match"
			}
			else if(params.password.length() < 6) {
				flash.message = "Passwords must be a minimum of 6 characters "
			}
			else {
				//def user = new User(params)
				user.username = user.username.toUpperCase()
				user.passwordHash = shiroSecurityService.encodePassword(params.password)
				user.status = User.Status.PENDING_EMAIL_ACTIVICATION
				user.addToRoles(Role.findByName("user"))
				if (!user.save(flush:true)) {
					log.info "validation failed"
					render (view: 'register', model: [userInstance: user])
					flash.message = null
					return
				}
				
				def appURL = grailsApplication.config.grails.appURL
				String encrypted_value = URLEncoder.encode(Blowfish.encryptBase64("${user.username}&${params.password}", password), "ISO-8859-1")
				String activationURL = "${appURL}auth/activate?token=${encrypted_value}"
				log.info "activation url: ${activationURL}"
				flash.message= "Registeration Sussceesul! <br/> an activation link will send your email box. <br/> "+
						"<a href=\"${activationURL}\">${activationURL}</a>"
				try{	
					mailService.sendMail {
						to user.email
						from "mpems.mastercard@gmail.com"
						subject "MasterCard MPEMS registration"
						body "Dear user, \n Thank you to register MPEMS. \n\n click below link to active your account: \n <a href=\"${activationURL}\">${activationURL}</a> \n\n Regards\nMasterCard MPEMS Team"
					 }
				}
				catch (e){
					log.info("email failed to send")
				}
			}
		}
		return [userInstance:user]
		
	}
	
	def resetPassword(){
		if(request.method == 'POST') {
			if (!params.email) {
				log.info "'email' not provided"
				flash.message= "You must provide a username!"
				render (model: [params:params])
				return
			}
			def user = User.findByEmail(params.email)
			if(!user) {
				log.info "no user acount found ${params.email}"
				return
			}
			def newPassword = generator( (('A'..'Z')+('0'..'9')).join(), 9 )
			user.passwordHash = shiroSecurityService.encodePassword(newPassword)
			userService.saveUser(user)
			try{
				mailService.sendMail {
					to user.email
					from "mpems.mastercard@gmail.com"
					subject "MasterCard MPEMS reset password"
					body "Dear user, \n new password: ${newPassword}"
				}
			}
			catch (e){
				log.info("email failed to send")
			}
			log.info "new password: ${newPassword}"
		}
		return [params:params]
	}
	
	def generator = { String alphabet, int n ->
		new Random().with {
		  (1..n).collect { alphabet[ nextInt( alphabet.length() ) ] }.join()
		}
	  }
	  
	
	def activate(){
		def type = params.type
		log.info "activation type ${type}"
		if(!type){
			flash.message = null
			def encrypted_key = params.token
			log.info "encrypted_key ${params.token}"
			def decrypt_value = (Blowfish.decryptBase64(encrypted_key, password))
			log.info "value = ${decrypt_value}"
			String [] username_password = decrypt_value.split("&")
			def authToken = new UsernamePasswordToken(username_password[0],username_password[1] as String)
			try {
				SecurityUtils.subject.login(authToken)
				def user = SecurityUtils.subject.session.getAttribute("current_user")
				user.status = User.Status.PENDING_PHONE_ACTIVATION
				userService.saveUser(user)
				log.info "mobile ${user.mobile}  ${user.username}"
				log.info "email activated"
				return [user:user]
			} catch (AuthenticationException ex){
				log.info "active failure for user"
			}
		}else if (type == "sms_otp"){
		log.info "username ${SecurityUtils.subject.principal}"
			def user = User.findByUsername(SecurityUtils.subject.principal)
			Random random = new Random()
			def otp = random.nextInt(1000000) 
			
//			def data = new URL("http://137.132.247.154:8888/SMS/send.aspx?rep=${user.mobile}&msg=OTP-${otp}").getText()
			smsService.send(user.mobile, "OTP-${otp}")
//			log.info "data =  ${data}, OTP-${otp}"
			def userActivationList = UserActivation.findAllByUser(user)
			def userActivation = null
			if (userActivationList){
			 	userActivation = userActivationList.get(0)
				userActivation.key = otp
				userActivation.createDt = new Date()
			}else {
				userActivation = new UserActivation(user:user, key:otp, createDt:new Date())
			}
			userActivation.save(flush:true,failOnError:true)
			flash.message = "OTP-${otp}"
			return [user:user]
		}else if (type == "sms_confirm"){
		
		log.info "sms_confirm ${SecurityUtils.subject.principal}"
			def user = User.findByUsername(SecurityUtils.subject.principal)
			log.info "user ${user}"
			def activationList = UserActivation.findAllByUser(user)
			if(activationList == null || activationList.size() == 0){
				log.warn "no activation list"
				flash.message='invalid otp'
				return [user:user]
			}else{
				def ua = activationList.get(0)
				log.info "userActivation ${ua.key}"
				if(params.key == ua.key){
					user.status = User.Status.ACTIVE
					userService.saveUser(user)
					log.info "user live"
					redirect (controller: "dashboard", action: "dashboard")
				}
			}
		}else{
			log.info "unknown operation type ${type}"
		}
	}
    def signIn = {
		log.info "=========signIn======"
        def authToken = new UsernamePasswordToken(params.username.toUpperCase(), params.password as String)

        // Support for "remember me"
        if (params.rememberMe) {
            authToken.rememberMe = true
        }
        
        // If a controller redirected to this page, redirect back
        // to it. Otherwise redirect to the root URI.
        def targetUri = params.targetUri ?: "/"
        
        // Handle requests saved by Shiro filters.
        def savedRequest = WebUtils.getSavedRequest(request)
        if (savedRequest) {
            targetUri = savedRequest.requestURI - request.contextPath
            if (savedRequest.queryString) targetUri = targetUri + '?' + savedRequest.queryString
        }
        
        try{
            // Perform the actual login. An AuthenticationException
            // will be thrown if the username is unrecognised or the
            // password is incorrect.
            SecurityUtils.subject.login(authToken)
			def user = SecurityUtils.subject.session.getAttribute("current_user")
			if(user.status == User.Status.ACTIVE){
				log.info "Redirecting to '${targetUri}'."
				user.loginDate = new Date()
				userService.saveUser(user)
				redirect(uri: targetUri)
			}else if(user.status == User.Status.PENDING_EMAIL_ACTIVICATION){
				log.info "Pending email activation '${params.username}'."
				SecurityUtils.subject?.logout()
				flash.message = "Account is not activated, please active it by click link sent to your email address"
				def m = [ username: params.username ]
				if (params.rememberMe) {
					m["rememberMe"] = true
				}
	
				// Remember the target URI too.
				if (params.targetUri) {
					m["targetUri"] = params.targetUri
				}
				redirect(action: "login", params: m)
			}else if(user.status == User.Status.PENDING_PHONE_ACTIVATION){
				render (view:"activate", model:[user:user])
			}else if(user.status == User.Status.INACTIVE){
				log.info "account is inactive '${params.username}'."
				SecurityUtils.subject?.logout()
				flash.message = "Account is not active, please contact our support @ mpems-mastercard@gmail.com"
				def m = [ username: params.username ]
				if (params.rememberMe) {
					m["rememberMe"] = true
				}
	
				// Remember the target URI too.
				if (params.targetUri) {
					m["targetUri"] = params.targetUri
				}
				redirect(action: "login", params: m)
			}else if(user.status == User.Status.LOCKED){
				log.info "account is locked '${params.username}'."
				SecurityUtils.subject?.logout()
				flash.message = "Account is locked, please contact our support @ mpems-mastercard@gmail.com"
				def m = [ username: params.username ]
				if (params.rememberMe) {
					m["rememberMe"] = true
				}

				// Remember the target URI too.
				if (params.targetUri) {
					m["targetUri"] = params.targetUri
				}
				redirect(action: "login", params: m)
			}
        }
        catch (AuthenticationException ex){
            // Authentication failed, so display the appropriate message
            // on the login page.
            log.info "Authentication failure for user '${params.username}'."
            flash.message = message(code: "login.failed")

            // Keep the username and "remember me" setting so that the
            // user doesn't have to enter them again.
            def m = [ username: params.username ]
            if (params.rememberMe) {
                m["rememberMe"] = true
            }

            // Remember the target URI too.
            if (params.targetUri) {
                m["targetUri"] = params.targetUri
            }

            // Now redirect back to the login page.
            redirect(action: "login", params: m)
        }
    }

    def signOut = {
        // Log the user out of the application.
        SecurityUtils.subject?.logout()

        // For now, redirect back to the home page.
        redirect(uri: "/")
    }
	def logout = {
		// Log the user out of the application.
		SecurityUtils.subject?.logout()

		// For now, redirect back to the home page.
		redirect(uri: "/auth/login")
	}
	

    def unauthorized = {
        render "You do not have permission to access this page."
    }
	
	def about = {
		render(view: "about")
	}
	
	def contactUs = {
		render(view: "contact_us")
	}
	
	def terms = {
		render(view: "terms")
	}
	
	def serverError = {
		render(view: "error")
	}
}
